﻿// BookClub.Model.cs
//

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using BookClub.Core;
using BookClub.Web.DataModel;
using BookClub.Web.Services;

namespace BookClub.Pages {

    public class BookClubModel : ViewModelBase {

        private ReferenceDataContext _referenceData;
        private BookClubContext _bookClubContext;

        private EntityQuery<BookInfo> _bookQuery;
        private string _heading;
        private string _status;
        private int _pageIndex;
        private bool _canShowMoreBooks;
        private BookInfo _selectedBook;

        private Category _searchCategory;
        private Category _dummyCategory;

        public BookClubModel() {
            _referenceData = new ReferenceDataContext();
            _dummyCategory = new Category() {
                CategoryName = "Browse by Category"
            };
            _searchCategory = _dummyCategory;
            _referenceData.Categories.Attach(_dummyCategory);
            _referenceData.Load(_referenceData.GetCategoriesQuery(), /* throwOnError */ false);

            _bookClubContext = new BookClubContext();

            ShowBooksOfDay();
        }

        public IEnumerable<BookInfo> Books {
            get {
                return _bookClubContext.BookInfos;
            }
        }

        public BookInfo SelectedBook {
            get {
                return _selectedBook;
            }
            set {
                if (_selectedBook != null) {
                    _selectedBook.IsSelected = false;
                }
                _selectedBook = value;
                if (_selectedBook != null) {
                    _selectedBook.IsSelected = true;
                }
                RaisePropertyChanged("SelectedBook");
            }
        }

        public IEnumerable<Category> Categories {
            get {
                return _referenceData.Categories;
            }
        }

        public Category SearchCategory {
            get {
                return _searchCategory;
            }
            set {
                _searchCategory = value;

                if (_searchCategory == _dummyCategory) {
                    return;
                }

                Heading = _searchCategory.CategoryName + " Books";
                _bookQuery = _bookClubContext.GetLatestBooksQuery().Where(b => b.CategoryID == _searchCategory.CategoryID);
                _pageIndex = 0;
                LoadBooks(_bookQuery, /* enablePaging */ true);
            }
        }

        public string Heading {
            get {
                return _heading;
            }
            set {
                _heading = value;
                RaisePropertyChanged("Heading");
            }
        }

        public string Status {
            get {
                return _status;
            }
            set {
                _status = value;
                RaisePropertyChanged("Status");
            }
        }

        public void ShowBooksOfDay() {
            Heading = "The Book of the Day, and other similar books...";

            _bookQuery = _bookClubContext.GetBookOfTheDayQuery();
            _pageIndex = 0;
            LoadBooks(_bookQuery, /* enablePaging */ false);
        }

        public void ShowLatestBooks() {
            Heading = "Latest additions...";

            _bookQuery = _bookClubContext.GetLatestBooksQuery();
            _pageIndex = 0;
            LoadBooks(_bookQuery, /* enablePaging */ true);
        }

        public void SearchBooks(string searchText) {
            if (String.IsNullOrEmpty(searchText)) {
                return;
            }

            Heading = "Books matching '" + searchText + "'";
            _bookQuery = _bookClubContext.SearchBooksQuery(searchText);
            _pageIndex = 0;
            LoadBooks(_bookQuery, /* enablePaging */ true);
        }

        public bool CanShowMoreBooks {
            get {
                return _canShowMoreBooks;
            }
            set {
                _canShowMoreBooks = value;
                RaisePropertyChanged("CanShowMoreBooks");
            }
        }

        public void ShowMoreBooks() {
            _pageIndex++;
            LoadBooks(_bookQuery, /* enablePaging */ true);
        }

        private void LoadBooks(EntityQuery<BookInfo> query, bool enablePaging) {
            if (_pageIndex == 0) {
                _bookClubContext.BookInfos.Clear();
                SelectedBook = null;
            }
            else {
                query = query.Skip(_pageIndex * 5).Take(5);
            }

            CanShowMoreBooks = enablePaging;
            _bookClubContext.Load(query, delegate(LoadOperation<BookInfo> operation) {
                if (operation.HasError) {
                    Status = "There was an error loading the requested books. " + operation.Error.Message;
                    operation.MarkErrorAsHandled();
                }
                else {
                    BookInfo firstResult = operation.Entities.FirstOrDefault();
                    if (firstResult != null) {
                        SelectedBook = firstResult;
                    }
                }
            }, null);
        }

        public void RequestBook(BookInfo book) {
            book.RequestBook();

            _bookClubContext.SubmitChanges(delegate(SubmitOperation operation) {
                if (operation.HasError) {
                    string message = operation.Error.Message;

                    ValidationResult validationError = book.ValidationErrors.FirstOrDefault();
                    if (validationError != null) {
                        message = validationError.ErrorMessage;
                    }

                    _bookClubContext.RejectChanges();

                    Status = "Error requesting '" + book.Title + "'. " + message;
                    operation.MarkErrorAsHandled();
                }
                else {
                    Status = "Your request for '" + book.Title + "' has been recorded.";
                }
            }, null);
        }

        public void LikeBook(BookInfo book) {
            book.LikeBook();

            _bookClubContext.SubmitChanges(delegate(SubmitOperation operation) {
                if (operation.HasError) {
                    string message = operation.Error.Message;

                    ValidationResult validationError = book.ValidationErrors.FirstOrDefault();
                    if (validationError != null) {
                        message = validationError.ErrorMessage;
                    }

                    _bookClubContext.RejectChanges();

                    Status = "Error marking '" + book.Title + "' as a book you like. " + message;
                    operation.MarkErrorAsHandled();
                }
            }, null);
        }
    }
}
